package cond

import (
	"context"
	"sync"
	"sync/atomic"
	"unsafe"
)

type Cond struct {
	ch unsafe.Pointer
	l  sync.Locker
}

func NewCond(l sync.Locker) *Cond {
	ch := make(chan struct{}, 1)
	return &Cond{
		l:  l,
		ch: unsafe.Pointer(&ch),
	}
}

func (c *Cond) Wait() {
	ch := c.NotifyChan()
	c.l.Unlock()
	<-ch
	c.l.Lock()
	return
}

func (c *Cond) WaitV2(ctx context.Context) error {
	ch := c.NotifyChan()
	c.l.Unlock()
	select {
	case <-ch:
		c.l.Lock()
		return nil
	case <-ctx.Done():
		c.l.Lock()
		return ctx.Err()
	}
}

func (c *Cond) NotifyChan() chan struct{} {
	ptr := atomic.LoadPointer(&c.ch)
	return *((*chan struct{})(ptr))
}

func (c *Cond) Broadcast() {
	newCh := make(chan struct{}, 1)
	ptrOld := atomic.SwapPointer(&c.ch, unsafe.Pointer(&newCh))
	close(*(*chan struct{})(ptrOld))
}

// Signal 无法做到不丢弃信号且有超时控制
func (c *Cond) Signal() {
	ch := c.NotifyChan()
	select {
	case ch <- struct{}{}:
		// 成功发送信号
	default:
		// 已经有待处理的信号
	}
}
